package com.cold.demo.web.config;

import com.cold.demo.web.controller.Person;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.accept.ParameterContentNegotiationStrategy;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Predicate;

/**
 * @author: zyc
 */
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {


    public void configurePathMatch(PathMatchConfigurer configurer) {

    }


    // 配置内容协商选项
    // 使用这个功能需要在application.properties中开启 spring.mvc.contentnegotiation.favor-parameter=true
    // 默认情况下只要参数携带 format=json 就会返回对应的格式数据
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        // 请求：http://localhost/index?format=x-hello-test-111
        // 按照最佳匹配规则会匹配到 application/x-hello-test 类型的消息转换器进行转换
//        configurer.mediaType("test", MediaType.parseMediaType("application/x-hello-test;charset=UTF-8"));


        HashMap<String, MediaType> map = new HashMap<>();
        map.put("json", MediaType.APPLICATION_JSON);
        map.put("xml", MediaType.APPLICATION_XML);
        map.put("test", MediaType.parseMediaType("application/x-hello-test"));
        ParameterContentNegotiationStrategy parameterNegotiationStrategy = new ParameterContentNegotiationStrategy(map);
        parameterNegotiationStrategy.setParameterName("hh");

        HeaderContentNegotiationStrategy headerContentNegotiationStrategy = new HeaderContentNegotiationStrategy();

        configurer.strategies(Arrays.asList(parameterNegotiationStrategy, headerContentNegotiationStrategy));
    }

    // 消息转换器
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 添加一个自定义的消息转换器，默认通过请求头 Accept 字段来确定返回消息的格式
        /*HttpMessageConverter<Person> httpMessageConverter = new AbstractHttpMessageConverter<Person>(StandardCharsets.UTF_8,MediaType.parseMediaType("application/x-hello-test;charset=UTF-8")) {
            @Override
            protected boolean supports(Class<?> clazz) {
                return clazz.isAssignableFrom(Person.class);
            }
            @Override
            protected Person readInternal(Class<? extends Person> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
                return null;
            }
            @Override
            protected void writeInternal(Person person, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
                String content = person.getName() + ";"+person.getAge();
                outputMessage.getBody().write(content.getBytes());
            }
        };*/


        HttpMessageConverter<Person> httpMessageConverter = new HttpMessageConverter<Person>() {
            @Override
            public boolean canRead(Class<?> clazz, MediaType mediaType) {
                return clazz.isAssignableFrom(Person.class);
            }

            @Override
            public boolean canWrite(Class<?> clazz, MediaType mediaType) {
                return clazz.isAssignableFrom(Person.class);
            }

            @Override
            public List<MediaType> getSupportedMediaTypes() {
                MediaType mediaType = MediaType.parseMediaType("application/x-hello-test");
                return Collections.singletonList(mediaType);
            }

            @Override
            public Person read(Class<? extends Person> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
                InputStream body = inputMessage.getBody();
                return new Person();
            }

            @Override
            public void write(Person person, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
                ServletServerHttpResponse response = (ServletServerHttpResponse) outputMessage;
                String                    content  = person.getName() + ";" + person.getAge();
                outputMessage.getBody().write(content.getBytes());
                outputMessage.getBody().write("\n".getBytes());
                outputMessage.getBody().write(content.getBytes(StandardCharsets.UTF_8));
                outputMessage.getBody().write("\n".getBytes());
                outputMessage.getBody().write(content.getBytes(StandardCharsets.ISO_8859_1));
                outputMessage.getBody().write("\n".getBytes());
                outputMessage.getBody().write(content.getBytes("GBK"));
            }

        };

        converters.add(httpMessageConverter);
    }
}
